﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DatabaseLayer;

namespace Speakup
{
    /// <summary>
    /// ThemeLevel - is a pair of two level, MinLevel and MaxLevel.
    /// All level that fit [MinLevel,MaxLevel] are considered as sublevels for this theme level.
    /// 
    /// Note: ThemeLevel and Level are two different entities. 
    ///       ThemeLevel - is a range of Levels.
    /// </summary>     
    public struct ThemeLevel: IEquatable<ThemeLevel>, IComparable, IComparable<ThemeLevel>
    {
        const int MinLevelValue = 1;
        const int MaxLevelValue = 15;

        static public List<ThemeLevel> GetThemeLevels()
        {
            using (var dbCtx = DatabaseContextFactory.Create())
            {
                return GetThemeLevels();
            }
        }
        static public List<ThemeLevel> GetThemeLevels(SpeakupEntities dbCtx)
        {
            return (from n in dbCtx.Levels 
                    select new ThemeLevel
                    {
                        m_minLevel = n.MinLevel,
                        m_maxLevel = n.MaxLevel
                    }).ToList();
        }        

        static public ThemeLevel GetThemeLevel(int level)
        {
            using (var dbCtx = DatabaseContextFactory.Create())
            {
                return GetThemeLevel(level, dbCtx);
            }
        }
        static public ThemeLevel GetThemeLevel(int level, SpeakupEntities dbCtx)
        {
            var lvl = (from n in dbCtx.Levels
                       where n.MinLevel >= level && n.MaxLevel <= level
                       select n).FirstOrDefault();

            if (lvl == null) 
            {
                throw new ArgumentException("Specified level is not found in database");
            }
            return new ThemeLevel(lvl.MinLevel, lvl.MaxLevel);
        }

        public ThemeLevel(int minLevel, int maxLevel):this()            
        {
            m_minLevel = minLevel;
            m_maxLevel = maxLevel;
        }

        private int m_minLevel;
        public int MinLevel 
        {
            get
            {
                return m_minLevel;
            }

            internal set
            {
                if (value < MinLevelValue || value > MaxLevelValue)
                {
                    throw new ArgumentException("Level is out valid range");
                }

                if( value > MaxLevel)
                {
                    throw new ArgumentException("MinLevel is higher then MaxLevel");
                }

                m_minLevel = value;
            } 
        }

        private int m_maxLevel;
        public int MaxLevel 
        {
            get
            {
                return m_maxLevel;
            }

            internal set
            {
                if (value < MinLevelValue || value > MaxLevelValue)
                {
                    throw new ArgumentException("Level is out valid range");
                }

                if (value < MinLevel)
                {
                    throw new ArgumentException("MaxLevel is lower then MinLevel");
                }

                m_maxLevel = value;
            }
        }
        
        public bool ContainsLevel(int level)
        {
            return MinLevel <= level && level <= MaxLevel;
        }

        public override bool Equals(object obj)
        {
            ThemeLevel? rhs = obj as ThemeLevel?;
            if (rhs == null) return false;

            return Equals(rhs);
        }
        public bool Equals(ThemeLevel rhs)
        {
            if (ReferenceEquals(this, rhs))
                return true;

            return rhs.MinLevel == MinLevel && rhs.MaxLevel == MaxLevel;
        }

        public override int GetHashCode()
        {
            return MaxLevel << 16 | MinLevel;
        }
        public int CompareTo(object obj)
        {            
            return CompareTo((ThemeLevel)obj);
        }
        public int CompareTo(ThemeLevel rhs)
        {
            if(MinLevel == rhs.MinLevel)
            {
                return MaxLevel - rhs.MaxLevel;
            }
            return MinLevel - rhs.MinLevel;
        }
        public static bool operator ==(ThemeLevel lhs, ThemeLevel rhs)
        {
            return lhs.Equals(rhs);
        }
        public static bool operator !=(ThemeLevel lhs, ThemeLevel rhs)
        {
            return !lhs.Equals(rhs);
        }

        public override string ToString()
        {
            if (MinLevel == MaxLevel)
            {
                return String.Format("{0:00}",MinLevel);
            }

            return String.Format("{0:00}-{1:00}", MinLevel, MaxLevel);
        }
    } 
}
